// This source code is dual-licensed under the Apache License, version
// 2.0, and the Mozilla Public License, version 2.0.
//
// The APL v2.0:
//
//---------------------------------------------------------------------------
//   Copyright (c) 2007-2020 VMware, Inc.
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       https://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//---------------------------------------------------------------------------
//
// The MPL v2.0:
//
//---------------------------------------------------------------------------
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//
//  Copyright (c) 2007-2020 VMware, Inc.  All rights reserved.
//---------------------------------------------------------------------------

using System;
using System.Collections.Generic;

namespace RabbitMQ.Client.Impl
{
    ///<summary>Not part of the public API. Extension of IModel to
    ///include utilities and connection-setup routines needed by the
    ///implementation side.</summary>
    ///
    ///<remarks>This interface is used by the API autogeneration
    ///process. The AMQP XML specifications are read by the spec
    ///compilation tool, and after the basic method interface and
    ///implementation classes are generated, this interface is
    ///scanned, and a spec-version-specific implementation is
    ///autogenerated. Annotations are used on certain methods, return
    ///types, and parameters, to customise the details of the
    ///autogeneration process.</remarks>
    ///
    ///<see cref="RabbitMQ.Client.Impl.ModelBase"/>
    ///<see cref="RabbitMQ.Client.Framing.Impl.Model"/>
    internal interface IFullModel : IModel
    {
        ///<summary>Sends a Connection.TuneOk. Used during connection
        ///initialisation.</summary>
        void ConnectionTuneOk(ushort channelMax, uint frameMax, ushort heartbeat);

        ///<summary>Handle incoming Basic.Deliver methods. Dispatches
        ///to waiting consumers.</summary>
        void HandleBasicDeliver(string consumerTag,
            ulong deliveryTag,
            bool redelivered,
            string exchange,
            string routingKey,
            IBasicProperties basicProperties,
            ReadOnlyMemory<byte> body,
            byte[] rentedArray);

        ///<summary>Handle incoming Basic.Ack methods. Signals a
        ///BasicAckEvent.</summary>
        void HandleBasicAck(ulong deliveryTag, bool multiple);

        void HandleBasicCancel(string consumerTag, bool nowait);

        ///<summary>Handle incoming Basic.CancelOk methods.</summary>
        void HandleBasicCancelOk(string consumerTag);

        ///<summary>Handle incoming Basic.ConsumeOk methods.</summary>
        void HandleBasicConsumeOk(string consumerTag);

        ///<summary>Handle incoming Basic.GetEmpty methods. Routes the
        ///information to a waiting Basic.Get continuation.</summary>
        ///<remarks>
        /// Note that the clusterId field is ignored, as in the
        /// specification it notes that it is "deprecated pending
        /// review".
        ///</remarks>
        void HandleBasicGetEmpty();

        ///<summary>Handle incoming Basic.GetOk methods. Routes the
        ///information to a waiting Basic.Get continuation.</summary>
        void HandleBasicGetOk(ulong deliveryTag,
            bool redelivered,
            string exchange,
            string routingKey,
            uint messageCount,
            IBasicProperties basicProperties,
            ReadOnlyMemory<byte> body,
            byte[] rentedArray);

        ///<summary>Handle incoming Basic.Nack methods. Signals a
        ///BasicNackEvent.</summary>
        void HandleBasicNack(ulong deliveryTag, bool multiple, bool requeue);

        ///<summary>Handle incoming Basic.RecoverOk methods
        ///received in reply to Basic.Recover.
        ///</summary>
        void HandleBasicRecoverOk();

        ///<summary>Handle incoming Basic.Return methods. Signals a
        ///BasicReturnEvent.</summary>
        void HandleBasicReturn(ushort replyCode,
            string replyText,
            string exchange,
            string routingKey,
            IBasicProperties basicProperties,
            ReadOnlyMemory<byte> body,
            byte[] takeoverPayload);

        ///<summary>Handle an incoming Channel.Close. Shuts down the
        ///session and model.</summary>
        void HandleChannelClose(ushort replyCode, string replyText, ushort classId, ushort methodId);

        ///<summary>Handle an incoming Channel.CloseOk.</summary>
        void HandleChannelCloseOk();

        ///<summary>Handle incoming Channel.Flow methods. Either
        ///stops or resumes sending the methods that have content.</summary>
        void HandleChannelFlow(bool active);

        ///<summary>Handle an incoming Connection.Blocked.</summary>
        void HandleConnectionBlocked(string reason);

        ///<summary>Handle an incoming Connection.Close. Shuts down the
        ///connection and all sessions and models.</summary>
        void HandleConnectionClose(ushort replyCode, string replyText, ushort classId, ushort methodId);

        ///<summary>Handle an incoming Connection.OpenOk.</summary>
        void HandleConnectionOpenOk(string knownHosts);

        ///////////////////////////////////////////////////////////////////////////
        // Connection-related methods, for use in channel 0 during
        // connection startup/shutdown.

        ///<summary>Handle incoming Connection.Secure
        ///methods.</summary>
        void HandleConnectionSecure(byte[] challenge);

        ///<summary>Handle an incoming Connection.Start. Used during
        ///connection initialisation.</summary>
        void HandleConnectionStart(byte versionMajor, byte versionMinor, IDictionary<string, object> serverProperties, byte[] mechanisms, byte[] locales);

        ///<summary>Handle incoming Connection.Tune
        ///methods.</summary>
        void HandleConnectionTune(ushort channelMax, uint frameMax, ushort heartbeat);

        ///<summary>Handle an incominga Connection.Unblocked.</summary>
        void HandleConnectionUnblocked();

        ///<summary>Handle incoming Queue.DeclareOk methods. Routes the
        ///information to a waiting Queue.DeclareOk continuation.</summary>
        void HandleQueueDeclareOk(string queue, uint messageCount, uint consumerCount);

        ///<summary>Used to send a Basic.Cancel method. The public
        ///consume API calls this while also managing internal
        ///datastructures.</summary>
        void _Private_BasicCancel(string consumerTag, bool nowait);

        ///<summary>Used to send a Basic.Consume method. The public
        ///consume API calls this while also managing internal
        ///datastructures.</summary>
        void _Private_BasicConsume(string queue, string consumerTag, bool noLocal, bool autoAck, bool exclusive, bool nowait, IDictionary<string, object> arguments);

        ///<summary>Used to send a Basic.Get. Basic.Get is a special
        ///case, since it can result in a Basic.GetOk or a
        ///Basic.GetEmpty, so this level of manual control is
        ///required.</summary>
        void _Private_BasicGet(string queue, bool autoAck);

        ///<summary>Used to send a Basic.Publish method. Called by the
        ///public publish method after potential null-reference issues
        ///have been rectified.</summary>
        void _Private_BasicPublish(string exchange, string routingKey, bool mandatory, IBasicProperties basicProperties, ReadOnlyMemory<byte> body);

        void _Private_BasicRecover(bool requeue);

        ///<summary>Used to send a Channel.Close. Called during
        ///session shutdown.</summary>
        void _Private_ChannelClose(ushort replyCode, string replyText, ushort classId, ushort methodId);

        ///<summary>Used to send a Channel.CloseOk. Called during
        ///session shutdown.</summary>
        void _Private_ChannelCloseOk();

        ///<summary>Used to send a Channel.FlowOk. Confirms that
        ///Channel.Flow from the broker was processed.</summary>
        void _Private_ChannelFlowOk(bool active);

        ///<summary>Used to send a Channel.Open. Called during session
        ///initialisation.</summary>
        void _Private_ChannelOpen(string outOfBand);

        ///<summary>Used to send a Confirm.Select method. The public
        ///confirm API calls this while also managing internal
        ///datastructures.</summary>
        void _Private_ConfirmSelect(bool nowait);

        ///<summary>Used to send a Connection.Close. Called during
        ///connection shutdown.</summary>
        void _Private_ConnectionClose(ushort replyCode, string replyText, ushort classId, ushort methodId);

        ///<summary>Used to send a Connection.CloseOk. Called during
        ///connection shutdown.</summary>
        void _Private_ConnectionCloseOk();

        ///<summary>Used to send a Connection.Open. Called during
        ///connection startup.</summary>
        void _Private_ConnectionOpen(string virtualHost, string capabilities, bool insist);

        ///<summary>Used to send a Connection.SecureOk. Again, this is
        ///special, like Basic.Get.</summary>
        void _Private_ConnectionSecureOk(byte[] response);

        ///<summary>Used to send a Connection.StartOk. This is
        ///special, like Basic.Get.</summary>
        void _Private_ConnectionStartOk(IDictionary<string, object> clientProperties, string mechanism, byte[] response, string locale);

        ///<summary>Used to send a Conection.UpdateSecret method. Called by the
        ///public UpdateSecret method.
        ///</summary>
        void _Private_UpdateSecret(byte[] newSecret, string reason);

        ///<summary>Used to send a Exchange.Bind method. Called by the
        ///public bind method.
        ///</summary>
        void _Private_ExchangeBind(string destination, string source, string routingKey, bool nowait, IDictionary<string, object> arguments);

        ///<summary>Used to send a Exchange.Declare method. Called by the
        ///public declare method.
        ///</summary>
        void _Private_ExchangeDeclare(string exchange,
            string type,
            bool passive,
            bool durable,
            bool autoDelete,
            bool @internal,
            bool nowait,
            IDictionary<string, object> arguments);

        ///<summary>Used to send a Exchange.Delete method. Called by the
        ///public delete method.
        ///</summary>
        void _Private_ExchangeDelete(string exchange, bool ifUnused, bool nowait);

        ///<summary>Used to send a Exchange.Unbind method. Called by the
        ///public unbind method.
        ///</summary>
        void _Private_ExchangeUnbind(string destination, string source, string routingKey, bool nowait, IDictionary<string, object> arguments);

        ///<summary>Used to send a Queue.Bind method. Called by the
        ///public bind method.</summary>
        void _Private_QueueBind(string queue, string exchange, string routingKey, bool nowait, IDictionary<string, object> arguments);

        ///<summary>Used to send a Queue.Declare method. Called by the
        ///public declare method.</summary>
        void _Private_QueueDeclare(string queue,
            bool passive,
            bool durable,
            bool exclusive,
            bool autoDelete,
            bool nowait,
            IDictionary<string, object> arguments);

        ///<summary>Used to send a Queue.Delete method. Called by the
        ///public delete method.</summary>
        uint _Private_QueueDelete(string queue, bool ifUnused, bool ifEmpty, bool nowait);

        ///<summary>Used to send a Queue.Purge method. Called by the
        ///public purge method.</summary>
        uint _Private_QueuePurge(string queue, bool nowait);
    }

    ///<summary>Essential information from an incoming Connection.Tune
    ///method.</summary>
    internal struct ConnectionTuneDetails
    {
        ///<summary>The peer's suggested channel-max parameter.</summary>
        public ushort m_channelMax;

        ///<summary>The peer's suggested frame-max parameter.</summary>
        public uint m_frameMax;

        ///<summary>The peer's suggested heartbeat parameter.</summary>
        public ushort m_heartbeatInSeconds;
    }


    internal class ConnectionSecureOrTune
    {
        public byte[] m_challenge;
        public ConnectionTuneDetails m_tuneDetails;
    }
}
